/*
 * ________________________________________________________________________________________________________
 * Copyright (c) 2018-2019 InvenSense Inc. All rights reserved.
 *
 * This software, related documentation and any modifications thereto (collectively "Software") is subject
 * to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
 * and other intellectual property rights laws.
 *
 * InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
 * and any use, reproduction, disclosure or distribution of the Software without an express license agreement
 * from InvenSense is strictly prohibited.
 *
 * EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
 * PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
 * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
 * EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
 * INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
 * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
 * OF THE SOFTWARE.
 * ________________________________________________________________________________________________________
 */


#ifndef _ICM406XX_DRIVER_H
#define _ICM406XX_DRIVER_H

#ifdef __KERNEL__
#include <linux/kernel.h>
#include <linux/unistd.h>
#include <linux/types.h>
#include <linux/string.h>
#else
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#endif

#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/workqueue.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/delay.h>

#include <linux/time.h>
#include <linux/ktime.h>

#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif

#include "ICM-4x6xx.h"

#if defined(CONFIG_USE_QUALCOMM_HAL)
#include <linux/sensors.h>
#endif
/* sensor specific */
#define SENSOR_NAME "icm406xx"

#define SENSOR_CHIP_ID_ICM (0x38)
#define SENSOR_CHIP_ID_ICM_C2 (0xD1)
#define SENSOR_CHIP_ID_ICM_C3 (0xD3)

#define SENSOR_CHIP_REV_ID_ICM (0x00)

#define CHECK_CHIP_ID_TIME_MAX  5

#define ICM_REG_NAME(name) ICM406xx_##name##__REG
#define ICM_VAL_NAME(name) ICM406xx_##name
#define ICM_CALL_API(name) icm406xx_##name

#define ICM_I2C_WRITE_DELAY_TIME (1)

/* generic */
#define ICM_MAX_RETRY_I2C_XFER (10)
#define ICM_MAX_RETRY_WAKEUP (5)
#define ICM_MAX_RETRY_WAIT_DRDY (100)

#define ICM_DELAY_MIN (1)
#define ICM_DELAY_DEFAULT (200)

#define ICM_VALUE_MAX (32767)
#define ICM_VALUE_MIN (-32768)

#define BYTES_PER_LINE (16)

#define BUF_SIZE_PRINT (16)

#define ICM_FAST_CALI_TRUE  (1)
#define ICM_FAST_CALI_ALL_RDY (7)

/*! FIFO 1024 byte, max fifo frame count not over 150 */
#define FIFO_FRAME_CNT 170
#define FIFO_DATA_BUFSIZE    1024


#define FRAME_LEN_ACC    6
#define FRAME_LEN_GYRO    6
#define FRAME_LEN_MAG    8

/*! ICM Self test */
#define ICM_SELFTEST_AMP_HIGH       1

/* CMD  */
#define CMD_FOC_START                 0x03
#define CMD_PMU_ACC_SUSPEND           0x10
#define CMD_PMU_ACC_NORMAL            0x11
#define CMD_PMU_ACC_LP1               0x12
#define CMD_PMU_ACC_LP2               0x13
#define CMD_PMU_GYRO_SUSPEND          0x14
#define CMD_PMU_GYRO_NORMAL           0x15
#define CMD_PMU_GYRO_FASTSTART        0x17
#define CMD_PMU_MAG_SUSPEND           0x18
#define CMD_PMU_MAG_NORMAL            0x19
#define CMD_PMU_MAG_LP1               0x1A
#define CMD_PMU_MAG_LP2               0x1B
#define CMD_CLR_FIFO_DATA             0xB0
#define CMD_RESET_INT_ENGINE          0xB1
#define CMD_RESET_USER_REG            0xB6

#define USER_DAT_CFG_PAGE              0x00

/*! FIFO Head definition*/
#define FIFO_HEAD_A        0x84
#define FIFO_HEAD_G        0x88
#define FIFO_HEAD_M        0x90

#define FIFO_HEAD_G_A        (FIFO_HEAD_G | FIFO_HEAD_A)
#define FIFO_HEAD_M_A        (FIFO_HEAD_M | FIFO_HEAD_A)
#define FIFO_HEAD_M_G        (FIFO_HEAD_M | FIFO_HEAD_G)

#define FIFO_HEAD_M_G_A         (FIFO_HEAD_M | FIFO_HEAD_G | FIFO_HEAD_A)

#define FIFO_HEAD_SENSOR_TIME        0x44
#define FIFO_HEAD_SKIP_FRAME        0x40
#define FIFO_HEAD_OVER_READ_LSB       0x80
#define FIFO_HEAD_OVER_READ_MSB       0x00

/*! FIFO head mode Frame bytes number definition */
#define A_BYTES_FRM      6
#define G_BYTES_FRM      6
#define M_BYTES_FRM      8
#define GA_BYTES_FRM     12
#define MG_BYTES_FRM     14
#define MA_BYTES_FRM     14
#define MGA_BYTES_FRM    20

#define ACC_FIFO_HEAD       "acc"
#define GYRO_FIFO_HEAD     "gyro"
#define MAG_FIFO_HEAD         "mag"

/*! Invn sensor unknown place*/
#define BOSCH_SENSOR_PLACE_UNKNOWN (-1)
/*! Invn sensor remapping table size P0~P7*/
#define MAX_AXIS_REMAP_TAB_SZ 8

#define ENABLE     1
#define DISABLE    0

/* bmi sensor HW interrupt pin number */
#define ICM_INT0      0
#define ICM_INT1       1

#define ICM_INT_LEVEL      0
#define ICM_INT_EDGE        1

/*bmi fifo sensor type combination*/
enum ICM_FIFO_DATA_SELECT_T {
	ICM_FIFO_A_SEL = 1,
	ICM_FIFO_G_SEL,
	ICM_FIFO_G_A_SEL,
	ICM_FIFO_M_SEL,
	ICM_FIFO_M_A_SEL,
	ICM_FIFO_M_G_SEL,
	ICM_FIFO_M_G_A_SEL,
	ICM_FIFO_DATA_SEL_MAX
};

/*bmi interrupt about step_detector and sgm*/
#define INPUT_EVENT_STEP_DETECTOR    5
#define INPUT_EVENT_SGM              3/*7*/
#define INPUT_EVENT_FAST_ACC_CALIB_DONE    6
#define INPUT_EVENT_FAST_GYRO_CALIB_DONE    4


/*!
* Bst sensor common definition,
* please give parameters in BSP file.
*/
struct invn_sensor_specific {
	char *name;
	/* 0 to 7 */
	unsigned int place:3;
	int irq;
	int (*irq_gpio_cfg)(void);
};

/*! icm406xx sensor spec of power mode */
struct pw_mode {
	u8 acc_pm;
	u8 gyro_pm;
	u8 mag_pm;
};

/*! icm406xx sensor spec of odr */
struct odr_t {
	u8 acc_odr;
	u8 gyro_odr;
	u8 mag_odr;
};

/*! icm406xx sensor spec of range */
struct range_t {
	u8 acc_range;
	u8 gyro_range;
};

/*! icm406xx sensor error status */
struct err_status {
	u8 fatal_err;
	u8 err_code;
	u8 i2c_fail;
	u8 drop_cmd;
	u8 mag_drdy_err;
	u8 err_st_all;
};


/*! icm406xx fifo sensor time */
struct fifo_sensor_time_t {
	u32 acc_ts;
	u32 gyro_ts;
	u32 mag_ts;
};

struct pedometer_data_t {
	/*! Fix step detector misinformation for the first time*/
	u8 wkar_step_detector_status;
	u_int32_t last_step_counter_value;
};

struct icm_client_data {
	struct icm406xx_t device;
	struct device *dev;
	struct input_dev *input;/*acc_device*/
#if defined(CONFIG_USE_QUALCOMM_HAL)
	struct input_dev *gyro_input;
	struct sensors_classdev accel_cdev;
	struct sensors_classdev gyro_cdev;
	struct delayed_work accel_poll_work;
	struct delayed_work gyro_poll_work;
	u32 accel_poll_ms;
	u32 gyro_poll_ms;
	u32 accel_latency_ms;
	u32 gyro_latency_ms;
	atomic_t accel_en;
	atomic_t gyro_en;
	struct workqueue_struct *data_wq;
#endif
	struct delayed_work work;
	struct work_struct irq_work;

	u8 chip_id;

	struct pw_mode pw;
	struct odr_t odr;
	struct range_t range; /*TO DO*/
	struct err_status err_st;
	struct pedometer_data_t pedo_data;
	s8 place;
	u8 selftest;

	atomic_t wkqueue_en; /*TO DO acc gyro mag*/
	atomic_t delay;
	atomic_t selftest_result;

	u8  fifo_data_sel;
	u16 fifo_bytecount;
	u8 fifo_head_en;
	unsigned char fifo_int_tag_en;

	unsigned char *fifo_data;
	u64 fifo_time;
	u8 stc_enable;
	uint16_t gpio_pin;
	u8 std;
	u8 sig_flag;
	unsigned char calib_status;
	struct mutex mutex_op_mode;
	struct mutex mutex_enable;
	struct invn_sensor_specific *bst_pd;
	int IRQ;
	int reg_sel;
	int reg_len;
#ifdef CONFIG_HAS_EARLYSUSPEND
	struct early_suspend early_suspend_handler;
#endif
};


s8 icm_burst_read_wrapper(u8 dev_addr, u8 reg_addr, u8 *data, u16 len);
int icm_probe(struct icm_client_data *client_data, struct device *dev);
int icm_remove(struct device *dev);
int icm_suspend(struct device *dev);
int icm_resume(struct device *dev);




#endif/*_ICM406XX_DRIVER_H*/
/*@}*/

